﻿namespace Player.Views
{
    using System;
    using System.Windows.Forms;

    using Common.ChartDrawing;
    using Common.EventArg;
    using Common.Helpers;
    using Common.Interfaces;
    using Common.Localization;
    using Common.Protocol;
    using Player.Models;
    using UI;

    public partial class MainView : ViewBase
    {
        private WaitMessage message;
        private ExtendedCell extendedCell;
        private bool extendedCellEnabled = false;

        private MainViewModel model;

        public event EventHandler CloseWindowClicked;

        public MainView()
        {
            this.InitializeComponent();

            this.chart.DateTimeChanged += this.ChartDateTimeChangedEventHandler;
            this.chart.RedLinePositionChanged += this.ChartRedLinePositionChangedEventHandler;
            this.chart.CenterCharts += this.ChartCenterChartsEventHandler;
            this.chart.ScaleChanged += this.ChartScaleChangedEventHandler;
            this.channelSwitcher1.Enabled = false;
            this.channelSwitcher1.ChannelStateSwitched += this.ChannelStateSwitchedEventHandler;
        }

        private void AsyncOpeningCompleteEventHandler()
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action(this.Initialize));
            }
        }

        public void Initialize()
        {
            if (this.model != null)
            {
                this.model = new MainViewModel(
                    new ChartScale
                    {
                        StepMilliseconds = this.model.Interval.StepMilliseconds,
                        TotalMilliseconds = (int)this.model.Interval.TotalMilliseconds
                    });
            }
            else
            {
                this.model = new MainViewModel();
            }

            ChannelDispatcher.Reset();
            this.cellContainer.Clear();
            this.InitCellContainer(this.model.Interval.CurrentBlock.Id, this.model.Interval.CurrentBlock);
            this.chart.Initialize(this.model.Interval);
            this.cellContainer.RefreshChanelValues(this.model.Interval.CurrentTime);
            this.channelSwitcher1.Enabled = true;
            this.channelSwitcher1.Initialize(this.model.Interval.CurrentBlock);
            this.HideWaitMessage();
        }

        public void ChannelStateSwitchedEventHandler(object sender, EventArgs e)
        {
            this.cellContainer.Clear();

            foreach (var channel in this.model.Interval.CurrentBlock.Channels)
            {
                if (ChannelDispatcher.IsActive(channel.Id))
                {
                    Cell c = new Cell();
                    c.Initialize(channel);
                    this.cellContainer.AddCell(c);
                }
            }

            this.chart.Initialize(this.model.Interval);
            this.cellContainer.RefreshChanelValues(this.model.Interval.CurrentTime);
        }

        #region chart event handlers

        private void ChartDateTimeChangedEventHandler(object sender, DateTimeEventArgs e)
        {
            DateTime timeToNavigate = Protocol.FindClosestTime(e.Time);

            if (timeToNavigate != e.Time)
            {
                string message = e.Time.ToLongTimeString() + "  " + e.Time.ToShortDateString() + Environment.NewLine
                                 + LocalizationProvider.GetMessage("time_not_found") + Environment.NewLine
                                 + LocalizationProvider.GetMessage("navigate_to_closest") + Environment.NewLine
                                 + timeToNavigate.ToLongTimeString() + "  " + timeToNavigate.ToShortDateString();
                var result = MessageBox.Show(message, string.Empty, MessageBoxButtons.YesNo);
                if (result == DialogResult.Yes)
                {
                    this.InitWithCurrentScale(timeToNavigate);
                }
                else
                {
                    this.chart.SetNavigationPanelTime(Constants.CurrentTime);
                }
            }
            else
            {
                this.InitWithCurrentScale(timeToNavigate);
            }
        }

        private void InitWithCurrentScale(DateTime timeToNavigate)
        {
            ProtocolInterval i = new ProtocolInterval(timeToNavigate, this.model.Interval.TotalMilliseconds, this.model.Interval.StepMilliseconds);
            if (this.model.Interval.CurrentBlock.Id != i.CurrentBlock.Id)
            {
                this.cellContainer.Clear();
                this.InitCellContainer(i.CurrentBlock.Id, i.CurrentBlock);
                this.channelSwitcher1.Initialize(i.CurrentBlock);
            }

            this.model.Interval = i;
            this.chart.Initialize(i);
            this.cellContainer.RefreshChanelValues(i.CurrentTime);
        }

        private void ChartRedLinePositionChangedEventHandler(object sender, DateTimeEventArgs e)
        {
            if (!(this.model.Interval.CurrentBlock.Start <= e.Time
                && this.model.Interval.CurrentBlock.End >= e.Time))
            {
                this.cellContainer.Clear();

                this.model.Interval.CurrentBlock = this.model.Interval.Blocks.Find(b => b.Start <= e.Time && b.End >= e.Time);
                this.InitCellContainer(this.model.Interval.CurrentBlock.Id, this.model.Interval.CurrentBlock);
                this.channelSwitcher1.Initialize(this.model.Interval.CurrentBlock);
                this.model.Interval.CurrentTime = e.Time;
            }

            this.cellContainer.RefreshChanelValues(e.Time);
        }

        private void ChartScaleChangedEventHandler(object sender, ChartScaleEventArgs e)
        {
            ProtocolInterval i = new ProtocolInterval(this.model.Interval.CurrentTime, e.Scale.TotalMilliseconds, e.Scale.StepMilliseconds);
            this.model.Interval = i;
            this.chart.Initialize(i);
        }

        private void ChartCenterChartsEventHandler(object sender, EventArgs e)
        {
            ProtocolInterval i = new ProtocolInterval(this.model.Interval.CurrentTime, this.model.Interval.TotalMilliseconds, this.model.Interval.StepMilliseconds);
            this.model.Interval = i;
            this.chart.Initialize(i);
        }

        #endregion

        public override void Localize()
        {
            this.chart.Localize();
            this.cellContainer.Localize();
            this.LocalizeToolStripMenu();
        }

        private void LocalizeToolStripMenu()
        {
            this.fileToolStripMenuItem.Text = LocalizationProvider.GetMessage("file");
            this.exitToolStripMenuItem.Text = LocalizationProvider.GetMessage("exit");
            this.openToolStripMenuItem.Text = LocalizationProvider.GetMessage("open");
        }

        private void InitCellContainer(int blockId, Block block)
        {
            Block b = Protocol.Blocks.Find(x => x.Id == blockId);

            foreach (var channel in b.Channels)
            {
                if (ChannelDispatcher.IsActive(channel.Id))
                {
                    Cell c = new Cell();
                    c.Initialize(channel);
                    this.cellContainer.AddCell(c);
                }
            }
        }

        #region toolStripMenu items events

        private void OpenToolStripMenuItemClick(object sender, EventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Multiselect = false;
            dlg.Filter = @"Protocol files (*.dat)|*.dat|All files (*.*)|*.*";
            DialogResult result = dlg.ShowDialog();

            if (result == DialogResult.OK)
            {
                Reader.Close();
                Reader.Open(dlg.FileName);

                AsyncActionWrapper asyncReading = new AsyncActionWrapper(Reader.Read);
                GC.KeepAlive(asyncReading);
                asyncReading.ActionComplited += (o, args) => this.AsyncOpeningCompleteEventHandler();
                this.ShowWaitMessage();
                asyncReading.Start();
            }
        }

        private void ExitToolStripMenuItemClick(object sender, EventArgs e)
        {
            if (this.CloseWindowClicked != null)
            {
                this.CloseWindowClicked(this, null);
            }
        }

        #endregion

        #region extended cell

        private void ShowExtendedCell(object sender, EventArgs e)
        {
            if (this.extendedCellEnabled)
            {
                this.extendedCell.Cell = sender as Cell;
            }
            else
            {
                this.extendedCellEnabled = true;
                this.extendedCell = new ExtendedCell(sender as Cell);
                int top = cellContainer.Top;
                int left = cellContainer.Left;
                this.extendedCell.Top = top;
                this.extendedCell.Left = left;
                this.extendedCell.Close += this.HideExtendedCell;
                this.cellContainer.Top = this.extendedCell.Bottom + 2 * Cell.Margin;
                this.cellContainer.Height = this.ClientRectangle.Height - this.extendedCell.Height
                    - this.menuStrip1.Height - 2 * Cell.Margin;
                this.Controls.Add(this.extendedCell);
            }
        }

        private void HideExtendedCell(object sender, EventArgs e)
        {
            this.extendedCellEnabled = false;
            this.Controls.Remove(this.extendedCell);
            this.extendedCell = null;

            this.cellContainer.Top = this.menuStrip1.Bottom;
            this.cellContainer.Height = this.ClientRectangle.Height - this.menuStrip1.Height;
        }

        #endregion

        #region wait message

        private void ShowWaitMessage()
        {
            this.Cursor = Cursors.WaitCursor;
            this.chart.Hide();
            this.cellContainer.Hide();
            this.channelSwitcher1.Hide();
            this.menuStrip1.Hide();

            if (this.extendedCell != null)
            {
                this.extendedCell.Hide();
            }

            this.message = new WaitMessage("wait");
            this.message.BringToFront();
            this.message.Anchor = AnchorStyles.None;
            this.message.Top = this.ClientSize.Height / 2 - this.message.Height / 2;
            this.message.Left = this.ClientSize.Width / 2 - this.message.Width / 2;
            this.Controls.Add(this.message);
        }

        private void HideWaitMessage()
        {
            this.Cursor = Cursors.Arrow;
            this.chart.Show();
            this.cellContainer.Show();
            this.menuStrip1.Show();
            this.channelSwitcher1.Show();

            if (this.extendedCell != null)
            {
                this.extendedCell.Show();
            }

            if (this.message != null)
            {
                this.Controls.Remove(this.message);
            }
        }

        #endregion
    }
}